home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / MacPerl ƒ / Perl Source ƒ / MacPerl / MPConsole.cp < prev    next >
Text File  |  1994-01-19  |  9KB  |  443 lines

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Standalone Perl
  3. File        :    MPConsole.cp    -    Console interface for GUSI
  4. Author    :    Matthias Neeracher
  5. Started    :    31May93                                Language    :    MPW C/C++
  6. Modified    :    14Aug93    MN Remember rectangles    
  7.                 30Aug93    MN    ShowWindow -> DoShowWindow
  8. Last        :    30Aug93
  9. *********************************************************************/
  10.  
  11. #include "GUSI_P.h"
  12.  
  13. #include <Resources.h>
  14. #include <Windows.h>
  15. #include <Errors.h>
  16. #include <Folders.h>
  17. #include <PLStringFuncs.h>
  18. #include <SysEqu.h>
  19. #include <OSEvents.h>
  20.  
  21. #include <ioctl.h>
  22. #include <sys/types.h>
  23. #include <Signal.h>
  24.  
  25. extern "C" {
  26. #include "MPConsole.h"
  27.  
  28. #include "MPGlobals.h"
  29. #include "MPAppleEvents.h"
  30. #include "MPWindow.h"
  31. #include "MPFile.h"
  32. #include "MPMain.h"
  33. }
  34.  
  35. #define AF_CONSOLE 17
  36.  
  37. class MPConsoleSocket;                             // That's what this file's all about
  38.  
  39. class MPConsoleSocket : public Socket    {        
  40.     friend class MPConsoleSocketDomain;    
  41.     friend void CloseConsole(Ptr cookie);
  42.     friend void HarvestConsole(DPtr doc, MPConsoleSocket * sock);
  43.     friend int GUSIConsoleSpin(spin_msg msg, long arg);
  44.     
  45.                     MPConsoleSocket(DPtr window);
  46.                     
  47.     virtual         ~MPConsoleSocket();
  48.     
  49.     DPtr                    window;
  50.     Handle                input;
  51.     Boolean                nonblocking;
  52.     Boolean                eof;
  53. public:
  54.     virtual int    read(void * buffer, int buflen);
  55.     virtual int write(void * buffer, int buflen);
  56.     virtual int    fcntl(unsigned int cmd, int arg);
  57.     virtual void pre_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
  58.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  59.     virtual void post_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
  60.     virtual int    ioctl(unsigned int request, void *argp);
  61.     virtual int    isatty();
  62. };    
  63.  
  64. class MPConsoleSocketDomain : public DeviceSocketDomain {
  65.     MPConsoleSocket *    first;
  66. public:
  67.     MPConsoleSocketDomain()    :    DeviceSocketDomain(AF_CONSOLE)    {    }
  68.     
  69.     virtual     Socket * open(const char * filename, int oflag);
  70. };
  71.  
  72. MPConsoleSocketDomain    MPConsoleSockets;
  73.  
  74. #pragma segment MPConsole
  75.  
  76. /************************ MPConsoleSocket members ************************/
  77.  
  78. void HarvestConsole(DPtr doc, MPConsoleSocket * sock)
  79. {                
  80.     HLock((*doc->theText)->hText);
  81.     
  82.     char * chr = *(*doc->theText)->hText + (*doc->theText)->teLength;
  83.     char * end = *(*doc->theText)->hText + doc->u.cons.fence;
  84.  
  85.     if (gGotEof == doc) {
  86.         PtrAndHand(end, sock->input, chr - end);
  87.         
  88.         doc->u.cons.fence = (*doc->theText)->teLength;
  89.         sock->eof            = true;
  90.     } else 
  91.         while (chr-- > end)
  92.             if (*chr == '\n') {
  93.                 PtrAndHand(end, sock->input, ++chr - end);
  94.                 doc->u.cons.fence = chr - *(*doc->theText)->hText;
  95.                 
  96.                 break;
  97.             }
  98.     
  99.     HUnlock((*doc->theText)->hText);
  100. }
  101.  
  102. MPConsoleSocket::MPConsoleSocket(DPtr window)
  103.     : window(window)
  104. {
  105.     nonblocking                    =    false;
  106.     eof                            =    false;
  107.     input                            =    NewHandle(0);
  108.     window->u.cons.cookie    =    Ptr(this);
  109. }
  110.  
  111. void CloseConsole(Ptr cookie)
  112. {
  113.     if (cookie)
  114.         ((MPConsoleSocket *) cookie)->window = nil;
  115. }
  116.  
  117. MPConsoleSocket::~MPConsoleSocket()
  118. {
  119.     DisposeHandle(input);
  120.     
  121.     if (window)
  122.         window->u.cons.cookie    = nil;
  123. }
  124.  
  125. int MPConsoleSocket::fcntl(unsigned int cmd, int arg)
  126. {
  127.     switch (cmd)    {
  128.     case F_GETFL:
  129.         if (nonblocking)
  130.             return FNDELAY;
  131.         else
  132.             return 0;
  133.     case F_SETFL:
  134.         if (arg & FNDELAY)
  135.             nonblocking = true;
  136.         else
  137.             nonblocking = false;
  138.             
  139.         return 0;
  140.     default:
  141.         return GUSI_error(EOPNOTSUPP);
  142.     }
  143. }
  144.  
  145. int MPConsoleSocket::ioctl(unsigned int request, void *argp)
  146. {
  147.     switch (request)    {
  148.     case FIONBIO:
  149.         nonblocking    =    (Boolean) *(long *) argp;
  150.         
  151.         return 0;
  152.     case FIONREAD:
  153.         *(unsigned long *) argp    = GetHandleSize(input);
  154.         
  155.         return 0;
  156.     case FIOINTERACTIVE:
  157.         return 0;
  158.     case WIOSELECT:
  159.         if (window)
  160.             SelectWindow(window->theWindow);
  161.             
  162.         return 0;
  163.     default:
  164.         return GUSI_error(EOPNOTSUPP);
  165.     }
  166. }
  167.  
  168. int MPConsoleSocket::read(void * buffer, int buflen)
  169. {
  170.     int    avail;
  171.     
  172.     avail = int(GetHandleSize(input));
  173.     
  174.     if (!avail)    {
  175.         if (eof) {
  176.             eof = false;
  177.             
  178.             return 0;
  179.         }
  180.         if (!window)
  181.             return 0;
  182.         else if (nonblocking)
  183.             return GUSI_error(EWOULDBLOCK);
  184.         else {
  185.             if (!((WindowPeek) window->theWindow)->visible)
  186.                 DoShowWindow(window->theWindow);
  187.             if (!((WindowPeek) window->theWindow)->hilited)
  188.                 SelectWindow(window->theWindow);
  189.                 
  190.             window->u.cons.selected = true;
  191.             ShowWindowStatus();
  192.             
  193.             SPIN(!(avail = int(GetHandleSize(input))) && !eof && window, SP_STREAM_READ, 0);
  194.     
  195.             if (!avail && eof)
  196.                 eof = false;
  197.                 
  198.             window->u.cons.selected = false;
  199.             ShowWindowStatus();
  200.         }
  201.     }
  202.         
  203.     buflen = min(avail, buflen);
  204.     
  205.     HLock(input);
  206.     memcpy(buffer, *input, buflen);
  207.     if (avail -= buflen)
  208.         memcpy(*input, *input+buflen, avail);
  209.     HUnlock(input);
  210.     SetHandleSize(input, avail);
  211.     
  212.     return buflen;
  213. }
  214.  
  215. int MPConsoleSocket::write(void * buffer, int buflen)
  216. {
  217.     short    oldStart;
  218.     short    oldEnd;
  219.     int    len = buflen;
  220.     
  221.     if (!window)
  222.         return GUSI_error(ESHUTDOWN);
  223.  
  224.     HarvestConsole(window, this);
  225.     
  226.     if (len > window->u.cons.memory) {
  227.         buffer = (void *) (Ptr(buffer) + len - window->u.cons.memory);
  228.         len = window->u.cons.memory;
  229.     }
  230.     
  231.     (*window->theText)->teLength += buflen;
  232.     EnforceMemory(window, window->theText);
  233.     (*window->theText)->teLength -= buflen;
  234.     
  235.     oldStart    =    (*window->theText)->selStart;
  236.     oldEnd    =    (*window->theText)->selEnd;
  237.     
  238.     if (oldStart >= window->u.cons.fence)
  239.         oldStart += buflen;
  240.     if (oldEnd >= window->u.cons.fence)
  241.         oldEnd += buflen;
  242.         
  243.     TESetSelect(window->u.cons.fence, window->u.cons.fence, window->theText);
  244.     TEInsert(buffer, buflen, window->theText);
  245.  
  246.     if (!((WindowPeek) window->theWindow)->visible) {
  247.         HideControl(window->vScrollBar);
  248.         HideControl(window->hScrollBar);
  249.         
  250.         DoShowWindow(window->theWindow);
  251.     }
  252.  
  253.     ShowSelect(window);
  254.     DrawPageExtras(window);
  255.     
  256.     TESetSelect(oldStart, oldEnd, window->theText);
  257.  
  258.     if (window->u.cons.fence < 32767)
  259.         window->u.cons.fence += buflen;
  260.     
  261.     return buflen;
  262. }
  263.  
  264. static Boolean StatusNeedsUpdate = false;
  265.  
  266. void MPConsoleSocket::pre_select(Boolean canRead, Boolean, Boolean)
  267. {
  268.     if (canRead && window) {
  269.         StatusNeedsUpdate = window->u.cons.selected = true;
  270.         
  271.         if (!((WindowPeek) window->theWindow)->visible)
  272.             DoShowWindow(window->theWindow);
  273.     }
  274. }
  275.  
  276. void MPConsoleSocket::post_select(Boolean canRead, Boolean, Boolean)
  277. {
  278.     if (canRead && window)
  279.         StatusNeedsUpdate = window->u.cons.selected = false;
  280. }
  281.  
  282. int MPConsoleSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
  283. {
  284.     int        goodies     =     0;
  285.  
  286.     if (StatusNeedsUpdate) {
  287.         ShowWindowStatus();
  288.         
  289.         StatusNeedsUpdate = false;
  290.     }
  291.         
  292.     if (canRead)
  293.         if (*canRead = (GetHandleSize(input) > 0 || eof))
  294.             ++goodies;
  295.     
  296.     if (canWrite) {
  297.         *canWrite = true;
  298.         ++goodies;
  299.     }
  300.     
  301.     if (exception)
  302.         *exception = false;
  303.     
  304.     return goodies;
  305. }
  306.  
  307. int MPConsoleSocket::isatty()
  308. {
  309.     return 1;
  310. }
  311.  
  312. /********************* MPConsoleSocketDomain member **********************/
  313.  
  314. #pragma force_active on
  315.  
  316. static Boolean spinInstalled = false;
  317.  
  318. Socket * MPConsoleSocketDomain::open(const char * filename, int flags)
  319. {
  320.     DPtr                doc;
  321.     Socket *            sock = nil;
  322.     char                 title[256];
  323.     Boolean            nudoc = false;
  324.     
  325.     strncpy(title, filename, 7);
  326.     title[7] = 0;
  327.     
  328.     if (equalstring(title, (char *) "stdin", false, true)) {
  329.         flags = O_RDONLY;
  330.         
  331.         if (filename[5])
  332.             return (Socket *) TryNextDevice;
  333.         else
  334.             filename += 5;
  335.     } else if (equalstring(title, (char *) "stdout", false, true)) {
  336.         flags = O_WRONLY;
  337.         
  338.         if (filename[6])
  339.             return (Socket *) TryNextDevice;
  340.         else
  341.             filename += 6;
  342.     } else if (equalstring(title, (char *) "console", false, true)) {
  343.         switch (filename[7]) {
  344.         case ':':
  345.             ++filename;
  346.         case 0:
  347.             filename += 7;
  348.             break;
  349.         default:
  350.             return (Socket *) TryNextDevice;
  351.         }
  352.     } else
  353.         return (Socket *) TryNextDevice;
  354.  
  355.     if (*filename) {
  356.         for (doc = gConsoleList; doc; doc = doc->u.cons.next)
  357.             if (doc->kind == kConsoleWindow) {
  358.                 getwtitle(doc->theWindow, title);
  359.                 
  360.                 if (equalstring(title, (char *) filename, false, true)) {
  361.                     if (doc->u.cons.cookie)
  362.                         sock = (Socket *) doc->u.cons.cookie;
  363.  
  364.                     goto found;
  365.                 }
  366.             }
  367.             
  368.         nudoc    = true;                
  369.         doc    = NewDocument(false, kConsoleWindow);
  370.         
  371.         setwtitle(doc->theWindow, (char *) filename);
  372.         
  373.         RestoreConsole(doc);
  374.     } else {
  375.         for (doc = gConsoleList; doc; doc = doc->u.cons.next)
  376.             if (doc->kind == kWorksheetWindow) {
  377.                 if (doc->u.cons.cookie)
  378.                     sock = (Socket *) doc->u.cons.cookie;
  379.  
  380.                 goto found;
  381.             }
  382.             
  383.         nudoc    = true;                
  384.         doc = NewDocument(false, kWorksheetWindow);
  385.         
  386.         SetWTitle(doc->theWindow, StringPtr(CurApName));
  387.  
  388.         RestoreConsole(doc);
  389.     }
  390.  
  391. found:    
  392.     if (!sock) {
  393.         errno = 0;
  394.         sock     = new MPConsoleSocket(doc);
  395.         
  396.         if (sock && errno) {
  397.             if (nudoc)
  398.                 CloseMyWindow(doc->theWindow);
  399.  
  400.             delete sock;
  401.             
  402.             return nil;
  403.         }
  404.  
  405.         if (!spinInstalled) {
  406.             GUSISetSpin(GUSIConsoleSpin);
  407.             
  408.             spinInstalled = true;
  409.         }
  410.     } else
  411.         ((MPConsoleSocket *)sock)->eof = false;
  412.  
  413.     if (!(flags & 1))
  414.         doc->u.cons.fence = (*doc->theText)->teLength;
  415.     else if (nudoc)
  416.         doc->u.cons.fence = 32767;
  417.  
  418.     return sock;
  419. }
  420.  
  421. /********************* A kinder, gentler, spin **********************/
  422.  
  423. int GUSIConsoleSpin(spin_msg spin, long)
  424. {
  425.     if (!gInBackground && GUSIInterrupt() && gRunningPerl) {
  426.         raise(SIGINT);
  427.         
  428.         /* Not reached */
  429.         return -1;
  430.     }
  431.         
  432.     MainEvent(spin != SP_SELECT && spin != SP_STREAM_READ);
  433.     
  434.     for (DPtr doc = gConsoleList; doc; doc = doc->u.cons.next)
  435.         if (doc->dirty) {
  436.             if (doc->u.cons.cookie) 
  437.                 HarvestConsole(doc, (MPConsoleSocket *) doc->u.cons.cookie);
  438.             doc->dirty = false;
  439.         }
  440.     
  441.     return 0;
  442. }
  443.